//
// Created by wrj on 2024/8/3.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netdb.h>
#include <errno.h>

#include "http.h"

int parser_task(const char *url, taskInfo *task)
{
    char *agreement,*location,*filename;
    agreement = strstr(url,"http://");
    if(agreement == NULL){
        fprintf(stderr,"NO http protocol header !\n");
        return -1;
    }
    agreement += strlen("http://");
    //现在agreement指针在 http://1153288396.rsc.cdn77.org/img/cdn77-test-563kb.jpg
    //                        |
    //                    agreement
    task->post =80;
    // 匹配1153288396.rsc.cdn77.org/img/cdn77-test-563kb.jpg 里面的第一个 /
    // 拿到主机名 1153288396.rsc.cdn77.org
    location = strstr(agreement,"/");
    if(location == NULL){
        fprintf(stderr,"URL format invalid! \n");
        return  -1;
    }
    *location =0;
    //1153288396.rsc.cdn77.org（0）img/cdn77-test-563kb.jpg
    //|                         |
    //agreement               location
    snprintf(task->hostname,sizeof (task->hostname),"%s",agreement);
    *location ='/';
    //1153288396.rsc.cdn77.org/img/cdn77-test-563kb.jpg
    //|                       |
    //agreement             location
    snprintf(task->res_path,sizeof (task->res_path),"%s",location);
    filename = location;
    while ((location=strstr(location +1,"/")) != NULL){
         filename =location;
        // 1153288396.rsc.cdn77.org/img/cdn77-test-563kb.jpg
        //                             |
        //                            filename
    }
    //跳过 / 只复制文件名
    snprintf(task->filename,sizeof (task->filename),"%s",filename+1);
    return  0;

}
taskInfo *createTask()
{
    taskInfo  *task = (taskInfo *)malloc(sizeof (taskInfo));
    //taskInfo  *task = malloc(sizeof (taskInfo));
    if(task == NULL){
        fprintf(stderr, "malloc error: %s\n", strerror(errno));;
        return  NULL;
    }
    memset(task,0,sizeof(taskInfo));
    return  task;
}
void releaseTask(taskInfo *task){
    if(task){
        free(task);
    }
}
int init_socket(taskInfo *task)
{
    int sock_fd;
    struct sockaddr_in dest;
    sock_fd = socket(AF_INET,SOCK_STREAM,0);
    if(sock_fd < 0){
        perror("socket : ");
        return  -1;
    }
    memset(&dest,0,sizeof(dest));
    dest.sin_family =AF_INET;
    dest.sin_port = htons(task->post);
    struct  hostent *pHostent = gethostbyname(task->hostname);
    if(pHostent ==NULL){
        fprintf(stderr,"get host name %d : %s\n" ,h_errno, hstrerror(h_errno));
        return  -1;
    }
    dest.sin_addr = *(struct in_addr *)pHostent->h_addr_list[0];
    int ret = connect(sock_fd,(const struct  sockaddr*)&dest,sizeof (dest));
    if(ret < 0){
        perror("connect : ");
        close(sock_fd);
        return -1;
    }
    fprintf(stdout,"connection success!\n");
    return  sock_fd;
}
HeaderBuffer *createHeaderBuffer(int size)
{
    HeaderBuffer *buffer =(HeaderBuffer* ) malloc(sizeof (HeaderBuffer));
    if(buffer == NULL){
        fprintf(stderr,"header buffer malloc  failed");
        return  NULL;
    }
    //数据存放的位置包括http请求
    buffer->header=(char *) malloc(sizeof(char *) *size);
    if (buffer->header == NULL) {
        free(buffer); // 如果 header 分配失败，释放 buffer
        fprintf(stderr, "header buffer header malloc failed\n");
        return NULL;
    }
    memset(buffer->header,0,sizeof(char)  * size);
    buffer->capacity =size;
    buffer->pos =0;
    return  buffer;
}
//http协议头
void add_request_start_line(HeaderBuffer *buffer, const char *method, const char *url)
{   int len;
    len = snprintf(buffer->header,buffer->capacity,"%s %s HTTP/1.1\r\n",method,url);
    buffer->pos += len;

}
//http协议行
void add_request_header(HeaderBuffer *buffer, const char *key, const char *value)
{
    int len;
    len = snprintf(buffer->header+buffer->pos,buffer->capacity-buffer->pos,"%s: %s\r\n",key,value);
    buffer->pos+= len;

}
//http结束标志
void add_request_end_line(HeaderBuffer *buffer)
{
    int len;
    len = snprintf(buffer->header+buffer->pos,buffer->capacity-buffer->pos,"\r\n");
    buffer->pos +=len;
    //但如果是截断的情况，就需要手动添加
    buffer->header[buffer->pos] =0;
}
//构建http请求消息
HeaderBuffer *build_request_header(taskInfo *task)
{
    HeaderBuffer *header = createHeaderBuffer(MAX_REQUEST_SIZE);
    if(header == NULL){
        return NULL;
    }
    add_request_start_line(header,"GET",task->res_path);
    add_request_header(header,"Accept-Language","zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6");
    add_request_header(header,"Host",task->hostname);
    add_request_header(header, "User-Agent",
                       "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 "
                       "Safari/537.36 Edg/114.0.1823.37");
    add_request_end_line(header);
    return  header;
}
void releaseHeaderBuffer(HeaderBuffer *buffer)
{
    if(buffer){
        if(buffer->header){
            free(buffer->header);
        }
        free(buffer);
    }
}
ssize_t send_data_bytes(int sock_fd, const void *_data, ssize_t len)
{
    ssize_t  cot =0;
    ssize_t  ret ;
    const char *date = _data;
    while (cot < len ){
        /*
         * data + cnt：指向要发送数据的指针
         * en - cnt：表示剩余要发送的字节数
         */
        ret = send(sock_fd,date+cot,len-cot,0);
        cot +=ret;
    }
    printf("send %ld/%ld bytes!\n", cot, len);
    if(cot ==len){
        return  0;
    } else{
        return -1;
    }
}
//收取http响应头判断是否成功接受完整
HeaderBuffer *rcv_response_header(int sock_fd)
{
    HeaderBuffer *response = createHeaderBuffer(MAX_RESPONSE_SIZE);
    if(response == NULL){
        return NULL;
    }
    ssize_t  ret;
    response->pos =0;
    ret = recv(sock_fd,response->header+response->pos,response->capacity-response->pos,0);
    if(ret < 0){
        perror("recv :");
        return  response;
    }
    response->pos+=ret;
    while (strstr(response->header,"\r\n\r\n") == NULL){
        ret = recv(sock_fd,response->header+response->pos,response->capacity-response->pos,0);
        if(ret < 0){
            perror("recv :");
            break;
        }
        response->pos+=ret;
        if(ret == 0){
            printf("remote closed! \n");
            break;
        }
    }

    return  response;
}
int get_status(HeaderBuffer *response)
{
    char *tmp = strstr(response->header,"HTTP/1.1 ");
    char *emdpoint;
    if(tmp ==NULL){
        return -1;
    }
    tmp+= strlen("HTTP/1.1 ");
    //jiang tmp指针指向的数据转换成10进制
    ssize_t status = strtol(tmp,&emdpoint,10);
    if(emdpoint[0] !=' '){
        fprintf(stderr,"str to unsigned long\n");
        return -1;
    }
    if(status != 200){
        printf("status: %ld, ready to exit!\n", status);
        return -1;
    }
    return 0;
}
//查找http响应头 是否是正确返回
void get_content_size(HeaderBuffer *response, const char *key, size_t *len)
{
    char  *start ,*end;
    ssize_t  t,cnt = 0;
    start = strstr(response->header,key);
    if(start == NULL){
        *len = 0;
        return;
    }
    end = strstr(start,"\r\n");
    if(end == NULL){
        *len = 0;
        return;
    }
    start += strlen(key);
    while (start < end){
        t =*start -'0';
        cnt = cnt * 10 + t;
        ++start;
    }
    *len=cnt;
}
size_t init_file(HeaderBuffer *response_header, int fd)
{
    char *tmp = strstr(response_header->header,"\r\n\r\n");
    if(tmp == NULL){
        return -1;
    }
    ssize_t  ret = 0;
    if (tmp -response_header->header + 4 == response_header->pos){
        printf("header no other data!\n");
        return  0;
    } else{
        ret = write(fd,tmp+4,response_header->pos-(tmp-response_header->header+4));
        if (ret < 0){
            perror("write: ");
            return -1;
        }
        printf("header other data: %ld",ret);
        return  ret;
    }

}
size_t receive_bytes(int sock_fd, int fd, size_t cnt_size)
{
    char  buf[2048];
    ssize_t ret,cnt =0;
    while (cnt < cnt_size) {
        ret = recv(sock_fd, buf, sizeof(buf), 0);
        if (ret < 0) {
            perror("recv : ");
            break;
        }
        ret = write(fd,buf,ret);
        cnt +=ret;
        printf("cnt =%ld\n",cnt);
    }
    printf("total size: %ld\n", cnt);
    return cnt;
}
